<?php

m2import('phpinchains/psp/ViewDispatcher.php');

class base_templateEngine_TemplateDispatcher extends ViewDispatcher {

    protected $compileDir;
    protected $namespaces;
    protected $basedir;
    protected $config;

    function __construct($psprootdir, $namespaces) {
        $this->compileDir = base_ApplicationContext::getInstance()->cfgPath('cacheDir') . 'templates'.DIRECTORY_SEPARATOR;
        $this->basedir    = $psprootdir;
        $this->config['namespaces'] = $namespaces;
        $this->config['psp-root-dir'] = $psprootdir;
        $this->initbasedir            = $this->config['psp-root-dir'].'/';
    }

    function dispatch($psppage, phpinchains_ActionForm $actionform = null) {
        $this->config['psp-page']     = $psppage;
        $ctx = phpinchains_ApplicationContext::getInstance();
        if ($actionform == null)
            $actionform = new phpinchains_ActionForm();
        $out = new phpinchains_psp_OutputWriter();
        $env = $ctx->getEnv();
        $dispatcher = $this;
        if ($this->config['psp-root-dir']) {
            $pspfile = "";
            $pspfile = $this->config['psp-root-dir'] . DIRECTORY_SEPARATOR . $this->config['psp-page'];
            $cfile   = $this->getCompileDir().DIRECTORY_SEPARATOR.$this->getPSPClassName($pspfile).'.php';
            $this->compilePSP($pspfile, $cfile);
            include($cfile);
        } else {
            throw new TemplateEngineException(
                    "TemplateDispatcher configuration error: No psp-root-dir specified!",
                    TemplateEngineException::$CONFIG_ERROR
                    );
        }
        return $out->getBuffer();
    }

    /**
     * Dispatch a compiled file directly
     *
     * @param string $file                        The file with path
     * @param phpinchains_ActionForm $actionform  Actionform
     * @return string Output of PSP
     */
    function dispatchRaw($file, phpinchains_ActionForm $actionform = null) {
        $ctx = phpinchains_ApplicationContext::getInstance();
        if ($actionform == null)
            $actionform = new phpinchains_ActionForm();
        $out = new phpinchains_psp_OutputWriter();
        $env = $ctx->getEnv();
        $dispatcher = $this;
        if (is_file($file)) {
            ob_start();
            include($file);
            $out->write(ob_get_contents());
            ob_end_clean();
        } else {
            throw new TemplateEngineException(
                    "TemplateDispatcher configuration error: Raw PSP not found '$file'!",
                    TemplateEngineException::$CONFIG_ERROR
                    );
        }
        return $out->getBuffer();
    }

    /**
     * Compiles the PSP and saves the result for further execution.
     * @param string $sfile Source file name
     * @param string $cfile Compiled destination file name
     * @param string $viewname Name of the view
     */
    function compilePSP($sfile, $cfile) {
        //$cfile = $sfile.'.psp';
        $ctx = & phpinchains_ApplicationContext::getInstance();
        $env = & $ctx->getEnv();
        //$env->setAttribute('__lastView', $viewname);
        if (!file_exists($sfile)) {
            throw new TemplateEngineException(
                    "<strong>FATAL ERROR:</strong> PSP $viewname.psp not found!",
                    TemplateEngineException::$TEMPLATE_NOT_FOUND
                    );
        } else {
            $sfile_stat = stat($sfile);
            if (!file_exists($cfile))
                $cfile_stat[9] = 0;
            else
                $cfile_stat = stat($cfile);
        }
        
        if ($cfile_stat[9] < $sfile_stat[9]) {
            $lex = new phpinchains_parser_psp_PSPLexer($GLOBALS['MODEL2_NS'], join("", file($sfile)), $sfile);
            $lex->lex();
            $parser = new phpinchains_parser_psp_PSPParser($lex, $this->basedir);
            $parser->parse();
            if (file_exists($cfile) && !is_writable($cfile)) {
                throw new TemplateEngineException(
                    "<strong>FATAL ERROR:</strong> File '$cfile' is not writeable!",
                    TemplateEngineException::$FILE_NOT_WRITEABLE
                    );
                return;
            }
            if (preg_match('#'.$this->getCompileDir().'#',$cfile)) {
                file_put_contents($cfile, '<?'.'php '."\n".'
        $relFilePaths[] = $this->relativeFilePath;
        $this->relativeFilePath = "'.substr($sfile, strlen($this->initbasedir)).'";

        '."\n".$parser->getCode().'
        $this->relativeFilePath = array_pop($relFilePaths);
         '."\n");
            } else
                throw new TemplateEngineException(
                    "<strong>FATAL ERROR:</strong> File '$cfile' not in compile dir '".$this->getCompileDir()." in TemplateDispatcher'!",
                    TemplateEngineException::$CONFIG_ERROR
                    );
        }
    }

    /**
     * Get file name for generated php file
     *
     * @param string $filename Absolute file name of psp file
     */
    function getPSPClassName($filename) {
        $str = str_replace('/', '__', substr($filename, strlen($this->basedir)+1, -4));
        return $str;
    }

    /**
     * Compile dir set?
     *
     * @return boolean If compile dir was set
     */
    function hasCompileDir() {
        return ($this->compileDir != null);
    }

    /**
     * Getter for compile dir
     *
     * @return string compile dir
     */
    function getCompileDir() {
        return $this->compileDir;
    }

    /**
     * Set content type to use in header
     *
     * @param string $type
     */
    function setContentType($type) {
        $cfgContentTypes['html'] = "text/html";
        $cfgContentTypes['svg'] = "image/svg+xml";
        $cfgContentTypes['xml'] = "text/xml";
        $cfgContentTypes['xhtml'] = "application/xhtml+xml";
        $cfgContentTypes['sgml'] = "application/sgml";
        $cfgContentTypes['txt'] = "text/plain";
        $cfgContentTypes['asc'] = "text/plain";
        $cfgContentTypes['tex'] = "application/x-tex";
        $cfgContentTypes['latex'] = "application/x-latex";
        $cfgContentTypes['jpeg'] = "image/jpeg";
        $cfgContentTypes['png'] = "image/png";
        $cfgContentTypes['sxw'] = "application/vnd.sun.xml.writer";
        $cfgContentTypes['sxc'] = "application/vnd.sun.xml.calc";
        $cfgContentTypes['sxi'] = "application/vnd.sun.xml.impress";
        $cfgContentTypes['pdf'] = "application/pdf";
        $cfgContentTypes['ps'] = "application/postscript";
        $cfgContentTypes['swf'] = "application/x-shockwave-flash";
        $cfgContentTypes['dvi'] = "application/x-dvi";
        $cfgContentTypes['csv'] = "text/csv";
        $cfgContentTypes['ics'] = "text/calendar";
        $cfgContentTypes['rss'] = "application/rss+xml";
        $cfgContentTypes['atom'] = "application/atom+xml";
        $cfgContentTypes['xls'] = "application/vnd.ms-excel";
        $cfgContentTypes['csv'] = "text/comma-separated-values";

        if (isset($cfgContentTypes[$type])) {
            $this->ctx->set('content-type', $cfgContentTypes[$type]);
        } else {
            $this->ctx->set('content-type', 'text/html');
        }
    }

    function sendContentType($type = '') {
        if (!$this->ctx->get('content-type-sent') && !headers_sent()) {
            $this->ctx->set('content-type-sent', true);
            if ($type) {
                header('Content-Type: ' . $type);
            } else {
                header('Content-Type: ' . $this->ctx->get('content-type'));
            }
        }
    }

}